/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.bpm.engine.impl.bpmn.behavior;

import com.je.bpm.engine.ActivitiException;
import com.je.bpm.engine.delegate.DelegateExecution;
import com.je.bpm.engine.impl.cmd.CompleteTaskCmd;
import com.je.bpm.engine.impl.context.Context;
import com.je.bpm.engine.impl.el.ExpressionManager;
import com.je.bpm.engine.impl.interceptor.CommandContext;
import com.je.bpm.engine.impl.persistence.entity.ExecutionEntity;
import com.je.bpm.engine.impl.persistence.entity.TaskEntity;
import com.je.bpm.engine.impl.persistence.entity.TaskEntityManager;
import org.apache.commons.lang3.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static java.util.Collections.emptyMap;

public class KaiteTaskActivityBehavior extends TaskActivityBehavior {

    @Override
    public void trigger(DelegateExecution execution, String signalName, Object signalData) {

        CommandContext commandContext = Context.getCommandContext();
        TaskEntityManager taskEntityManager = commandContext.getTaskEntityManager();
        List<TaskEntity> taskEntities = taskEntityManager.findTasksByExecutionId(execution.getId()); // Should be only one
        for (TaskEntity taskEntity : taskEntities) {
            if (!taskEntity.isDeleted()) {
                throw new ActivitiException("UserTask should not be signalled before complete");
            }
        }
        propagateVariablesToProcess(execution, commandContext);
        //执行离开操作
        leave(execution);
    }

    /**
     * 将变量传播到进程
     *
     * @param execution
     * @param commandContext
     */
    protected void propagateVariablesToProcess(DelegateExecution execution, CommandContext commandContext) {
        String processInstanceId = execution.getProcessInstanceId();
        ExecutionEntity processInstanceEntity = processInstanceId != null ? commandContext.getExecutionEntityManager().findById(processInstanceId) : null;
        if (processInstanceEntity != null) {
            Map<String, Object> taskVariables = new HashMap<>();
            if (commandContext.getCommand() instanceof CompleteTaskCmd) {
                taskVariables = ((CompleteTaskCmd) commandContext.getCommand()).getTaskVariables();
            }
            Map<String, Object> outboundVariables = calculateOutBoundVariables(execution, taskVariables);
            processInstanceEntity.setVariables(outboundVariables);
        }
    }

    /**
     * 处理分配
     *
     * @param taskEntityManager
     * @param assignee
     * @param owner
     * @param task
     * @param expressionManager
     * @param execution
     */
    protected void handleAssignments(TaskEntityManager taskEntityManager, String assignee, String owner, TaskEntity task, ExpressionManager expressionManager, DelegateExecution execution) {
        if (StringUtils.isNotEmpty(assignee)) {
            Object assigneeExpressionValue = expressionManager.createExpression(assignee).getValue(execution);
            String assigneeValue = null;
            if (assigneeExpressionValue != null) {
                assigneeValue = assigneeExpressionValue.toString();
            }
            taskEntityManager.changeTaskAssigneeNoEvents(task, assigneeValue);
        }

        if (StringUtils.isNotEmpty(owner)) {
            Object ownerExpressionValue = expressionManager.createExpression(owner).getValue(execution);
            String ownerValue = null;
            if (ownerExpressionValue != null) {
                ownerValue = ownerExpressionValue.toString();
            }
            taskEntityManager.changeTaskOwner(task, ownerValue);
        }
    }

    protected String getAssigneeIdByVar(String assignee, ExpressionManager expressionManager, DelegateExecution execution) {
        String assigneeValue = null;
        try {
            if (StringUtils.isNotEmpty(assignee)) {
                Object assigneeExpressionValue = expressionManager.createExpression(assignee).getValue(execution);
                if (assigneeExpressionValue != null) {
                    assigneeValue = assigneeExpressionValue.toString();
                }
            }
        } catch (Exception e) {
            return "";
        }
        return assigneeValue;
    }

    /**
     * 计算输入变量
     *
     * @param execution
     * @return
     */
    protected Map<String, Object> calculateInputVariables(DelegateExecution execution) {
        CommandContext commandContext = Context.getCommandContext();
        if (commandContext.getProcessEngineConfiguration().isCopyVariablesToLocalForTasks()) {
            return execution.getVariables();
        } else {
            return emptyMap();
        }
    }

    /**
     * 计算出界变量
     *
     * @param execution
     * @param taskVariables
     * @return
     */
    protected Map<String, Object> calculateOutBoundVariables(DelegateExecution execution, Map<String, Object> taskVariables) {
        CommandContext commandContext = Context.getCommandContext();
        if (commandContext.getProcessEngineConfiguration().isCopyVariablesToLocalForTasks()) {
            return taskVariables;
        }
        return emptyMap();
    }

}
